package cn.falcon.fmobi.console.interceptor;

import cn.falcon.fmobi.admin.entity.ShiroUser;
import cn.falcon.fmobi.biz.service.CustomerService;
import cn.falcon.fmobi.biz.vo.DomainUser;
import cn.falcon.fmobi.console.constant.UserRolePermission;
import cn.falcon.fmobi.console.exception.PermissionRefuseException;
import cn.falcon.fmobi.dao.po.Advertiser;
import cn.falcon.marketing.api.util.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.security.Principal;

/**
 * <p>模拟广告主登录的拦截器,该拦截器会在请求到达Controller之前对请求进行处理</p>
 * <p>拦截请求并根据请求中是否存在指定名称为 "imitateId" 的参数,如果存在表示该请求是一次模拟操作请求,</p>
 * <p>在拦截器中会将Session中存放的登录用户的信息改为当前被模拟广告主的信息,否则不改变Session中的值</p>
 * @author zhaohelong
 * @version 1.0
 */
public class ImitateAdvertiserInterceptor extends HandlerInterceptorAdapter {

    private static Logger logger= LoggerFactory.getLogger(ImitateAdvertiserInterceptor.class);

    @Autowired
    private CustomerService advertiserService;
    
    @Autowired
	MessageSource messageSource;
    
    private void requestLogger(HttpServletRequest request){
    	if(!request.getRequestURI().equals("/api/common/upload")){
    		RequestBody requestBody = new RequestBody();
        	requestBody.setUri(request.getRequestURI());
        	requestBody.setClientAddr(request.getRemoteAddr());
        	requestBody.setMethod(request.getMethod());
        	requestBody.setQueryString(request.getQueryString());
        	requestBody.setRequestMap(request.getParameterMap());
        	logger.info(JsonUtil.toJson(requestBody));
    	}
    }
    
    @Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
    	if(ex!=null){
    		logger.error(JsonUtil.toJson(ex));
    	}
		super.afterCompletion(request, response, handler, ex);
	}

	/**
     * 重写preHandle方法,在业务处理器处理请求之前进行拦截处理
     * @param request
     * @param response
     * @param handler 表示下一个拦截器或处理器
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        if(request.getRequestURI().indexOf("/fmobi/") != -1) {
            return true;
        }

    	requestLogger(request);
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        String imitateId=request.getParameter("imitateId");
        Integer imitId = null;
		try {
			if(StringUtils.isNotEmpty(imitateId))
			imitId = Integer.parseInt(imitateId);
		} catch (Exception e) {
			throw new PermissionRefuseException();
		}
        HttpSession session=request.getSession(false);
        if(session==null){
        	throw new PermissionRefuseException();
        }
        DomainUser domainUser=new DomainUser();
        //判断请求中是否存在imitateId
        if (imitateId!=null&&!"".equals(imitateId)){
            logger.info("========当前操作为模拟登录操作=========");
            //TODO 加入判断当模拟的广告主是否是该代理商下的广告主
            boolean b = advertiserService.agentExistAdvertiser(getActorId(UserRolePermission.USER_ROLE_AGENT),imitId );
            if (!b){
            	Principal principal = request.getUserPrincipal();
		         if(principal != null){
		        	 Subject subject = SecurityUtils.getSubject();
		        	 subject.logout();
		         }
            	throw new PermissionRefuseException();
            }
            Advertiser advertiser=advertiserService.getAdvertiserById(imitId);
            domainUser.setAdvertiserId(Integer.parseInt(imitateId));
            domainUser.setRoleName(UserRolePermission.USER_ROLE_ADVERTISER);
            domainUser.setName(advertiser.getCompanyName());
            session.setAttribute("loginUser",domainUser);
        }else{
            logger.info("========当前操作为正常登录操作=========");
            //不存在表示正常登录操作,从Shiro的Subject中获取登录用户信息
            domainUser.setAdvertiserId(getActorId(UserRolePermission.USER_ROLE_ADVERTISER));
            domainUser.setAgentId(getActorId(UserRolePermission.USER_ROLE_AGENT));
            ShiroUser user = getCurrentUser();
            if(user==null){
            	throw new PermissionRefuseException();
            }
            domainUser.setName(user.getName());
            domainUser.setRoleName(user.getRole());
            session.setAttribute("loginUser",domainUser);
        }
        return true;
    }

	/**
     * 获取当前登录用户的信息
     * @return
     */
    private ShiroUser getCurrentUser(){
        PrincipalCollection principal = SecurityUtils.getSubject().getPrincipals();
        if(principal==null){
            throw new PermissionRefuseException();
        }
        return principal.oneByType(ShiroUser.class);
    }

    /**
     * 判断用户是否具体roleName 的角色，有的话，返回该登录用户 对应 关系表的id
     * @param roleName
     * @return
     */
    private Integer getActorId(String roleName){
        if(hasRole(roleName)) return getCurrentUser().getActorId();
        return null;
    }

    /**
     * 验证用户是否包含角色 roleName
     * @return
     */
    private boolean hasRole(String... roleNames){
        for(String roleName:roleNames){
            if(SecurityUtils.getSubject().hasRole(roleName)) return true;
        }
        return false;
    }
}
